#include "ObjectHelper.h"
#include "GeometryObject.h"

class Sphere : public GeometryObject {
    vec3 location;
    float radius;
    vector<Transform> transforms;
    vector<Finish> finishes;
    
    public:
        Sphere() {
            location = vec3();
            radius = 0.0f;
            surfaceColor = Color();
        }
        
        Sphere(vec3 loc, float rad, Color c) {
            location = loc;
            radius = rad;
            surfaceColor = c;
        }
        
        Sphere(vector<string> input) {
            int index = 5;
            assert(input[0] == "sphere");
            
            istringstream(input[1]) >> location.x;
            istringstream(input[2]) >> location.y;
            istringstream(input[3]) >> location.z;
            
            istringstream(input[4]) >> radius;
            
            while (index < input.size()) {
                if (input[index] == "pigment") {
                    if (input[index + 1] == "color") {
                        if (input[index + 2] == "rgb") {
                            istringstream(input[index + 3]) >> surfaceColor.r;
                            istringstream(input[index + 4]) >> surfaceColor.g;
                            istringstream(input[index + 5]) >> surfaceColor.b;
                        }
                    }
                    else {
                        cout << "Bad keyword found in pigment Sphere: " << input[index + 1] << endl;
                        assert(0);
                    }
                    
                    index += 6;
                }
                else if (input[index] == "finish") {
                    index++;
                    while (index < input.size()) {
                        if (input[index] == "ambient") {
                            float value = 0.0f;
                            
                            istringstream(input[index + 1]) >> value;
                            finishes.push_back(Finish(Ambient, value));
                            
                            index += 2;                         
                        }
                        else if (input[index] == "diffuse") {
                            float value = 0.0f;
                            
                            istringstream(input[index + 1]) >> value;
                            finishes.push_back(Finish(Diffuse, value));
                            
                            index += 2; 
                        }
                        else {
                            break;
                        }
                    }
                }
                else if (input[index] == "translate") {
                    vec3 offset;
                    
                    istringstream(input[index + 1]) >> offset.x;
                    istringstream(input[index + 2]) >> offset.y;
                    istringstream(input[index + 3]) >> offset.z;
                    
                    transforms.push_back(Translate(offset));
                    
                    index += 4;
                }
                else if (input[index] == "scale") {
                    vec3 ratio;
                    
                    istringstream(input[index + 1]) >> ratio.x;
                    istringstream(input[index + 2]) >> ratio.y;
                    istringstream(input[index + 3]) >> ratio.z;
                    
                    transforms.push_back(Scale(ratio));
                    
                    index += 4;
                }
                else if (input[index] == "rotate") {
                    vec3 axis;
                    
                    istringstream(input[index + 1]) >> axis.x;
                    istringstream(input[index + 2]) >> axis.y;
                    istringstream(input[index + 3]) >> axis.z;
                    
                    transforms.push_back(Rotate(axis));
                    
                    index += 4;
                }
                else {
                    cout << "Bad keyword found in Sphere: " << input[index] << endl;
                    assert(0);
                }    
            }
        }
        
        /* A different geometric approach for ray-sphere collisions */
        bool intersect(vec3& rayOrigin, vec3& rayDirection, float* t0, float* t1) { 
		    vec3 ray = location - rayOrigin;
		    float radiusSquared = radius * radius;
		    float dotProd = glm::dot(ray, rayDirection);
		             
		    *t0 = 0.0f;
		    *t1 = 0.0f;
            
		    if (dotProd < 0) {
		        return false;
		    }    
		    
		    float dSquared = glm::dot(ray, ray) - (dotProd * dotProd);
		    
		    if (dSquared > radiusSquared) {
		        return false;
	        }
	        
		    float sqQuad = sqrtf(radiusSquared - dSquared);
		    if (t0 != NULL && t1 != NULL) {
			    *t0 = dotProd - sqQuad;
			    *t1 = dotProd + sqQuad;
		    }
		    
		    //printf("sphere %f\n", *t0);
		    
		    return true;
	    }
};
